import { GameConfig } from '../configs/GameConfig';
import { Attribute } from '../etc/Attribute';
import { util } from '../etc/Util';
import { CDTimer } from '../gameEtc/CDTimer';
import Appearance from '../model/Appearance';
import { MainUI } from '../ui/MainUI';
import { GrowModuleData, GrowModuleS } from './GrowModule';
import { LevelModuleC } from './LevelModule';

export class PlayerModuleData extends Subdata {
    @Decorator.persistence()
    reserveAttribute: Attribute.AttributeArray;
    
    get dataName(): string { return 'PlayerModuleData' }
    
    protected initDefaultData() {
        this.reserveAttribute = {};
        this.reserveAttribute[Attribute.EnumAttributeType.money] = 0;
        this.save(true);
    }
}

export class PlayerModuleC extends ModuleC<PlayerModuleS, PlayerModuleData>{
    // 即时属性存根(用于记录属性变更)
    private playerStashedAttrBuffer = {};
    // 即时属性容器
    private attribute: Attribute.AttributeValueObject = new Attribute.AttributeValueObject();

    onAddForceClear: Action = new Action()

    private levelMD:LevelModuleC

    private pushed: boolean = false
    private normalJumpForce = 500
    private extraForce: number = 0
    private addForceAttenuation:number = 0
    private extraMaxForce: number = 1000
    private sprintForce: number = 1000
    
    sprintCD:CDTimer = new CDTimer(2000)

    protected onStart() {
        this.levelMD = ModuleService.getModule(LevelModuleC)

        this.levelMD.onPlayerDeadEvent.add(this.onPlayerDead, this)

        this.data.onDataChange.add(this.onPlayerAttributeDataChanged, this);
        this.syncPlayerStashedAttribute();

        UIService.show(MainUI)

        InputUtil.onKeyDown(Keys.F6, ()=>{
            this.server.net_add_money()
        })
    }

    protected onUpdate(): void {
        const isJumping = this.localPlayer.character.isJumping
        // 在地面 并且 没有施加过冲量
        if (!isJumping && !this.pushed) {
            this.autoJump()
            this.pushed = true
        }
        // 在空中 并且 施加过冲量 则重置为可施加冲量状态
        if (isJumping && this.pushed) {
            this.pushed = false
        }
    }

    private onPlayerDead() {
        this.extraForce = 0
        this.onAddForceClear.call()
        // 清空左右冲量
        this.clearPlayerDirectionalImpulse()
    }

    private lastJumpPosition:Vector
    private autoJump() {
        let jumpForceAddiction = this.getAttr(Attribute.EnumAttributeType.jumpForceAddiction)
        let finalImpulse = (this.normalJumpForce + jumpForceAddiction) + this.extraForce + this.addForceAttenuation
        this.localPlayer.character.addImpulse(new Vector(0, 0, finalImpulse), true)

        SoundService.playSound('130809', 1, 0.05)

        // 添加冲量的衰减值
        if(this.extraForce > 0){
            this.addForceAttenuation = this.extraForce * 0.5
        }else{
            this.addForceAttenuation = this.addForceAttenuation * 0.5
        }

        this.lastJumpPosition = this.localPlayer.character.worldTransform.position

        // 额外冲量清空
        if (this.extraForce <= 0) return
        this.extraForce = 0
        this.onAddForceClear.call()

        // 额外冲量特效
        let jumpEffectScale = 0.5 + util.clamp(0, 1, this.extraForce / this.extraMaxForce) * 3
        EffectService.playOnGameObject('153612', this.localPlayer.character, {
            slotType: HumanoidSlotType.Root,
            scale: new Vector(jumpEffectScale, jumpEffectScale, jumpEffectScale),
            position: new Vector(0, 0, 180),
        })
    }

    getPlayerLastJumpPosition():Vector{
        return this.lastJumpPosition
    }

    injectForce(force: number) {
        let extraJumpForceAddition = this.getAttr(Attribute.EnumAttributeType.extraJumpForceAddition)
        this.extraForce = force * this.extraMaxForce + force * extraJumpForceAddition
    }

    sprint(){
        if(!this.sprintCD.canUse()) return

        // 先清除左右(只清除一半)
        let velocity = this.localPlayer.character.velocity
        this.localPlayer.character.addImpulse(new Vector(-velocity.x / 2, -velocity.y / 2, 0), true)

        let dir = Player.localPlayer.character.worldTransform.getForwardVector()

        let extraSprintForce = this.getAttr(Attribute.EnumAttributeType.extraSprintForce)
        dir = Vector.normalize(Vector.lerp(dir, Vector.up, 0.5))
        dir.multiply(this.sprintForce + extraSprintForce)
        this.localPlayer.character.addImpulse(dir, true)
        
        EffectService.playOnGameObject('153612', this.localPlayer.character, {
            slotType: HumanoidSlotType.Root,
            scale: new Vector(1, 1, 1),
            rotation: new Rotation(0,270,0),
            position: new Vector(60, 0, 90),
        })
    }

    // 清除玩家左右前后冲量
    clearPlayerDirectionalImpulse(){
        let velocity = this.localPlayer.character.velocity
        this.localPlayer.character.addImpulse(new Vector(-velocity.x, -velocity.y, 0), true)
    }

    // 获取玩家属性
    getAttr(type: Attribute.EnumAttributeType): number {
        if (!Attribute.IsStashAttribute(type)) return this.attribute.getValue(type)
        return this.data.reserveAttribute[type] || 0;
    }
    
    // 比对变更属性
    private onPlayerAttributeDataChanged() {
        for (let reserveAttributeKey in this.data.reserveAttribute) {
            let attrType = Number(reserveAttributeKey);
            // 当前的属性值
            let currentDataValue = this.data.reserveAttribute[attrType];
            // 上次的属性值(如果这个属性类型没有缓存则取0)
            let lastDataValue = this.playerStashedAttrBuffer[attrType] || 0
            // 增量
            let addVal = currentDataValue - lastDataValue;
            if (addVal <= 0) continue;
            // let attrCfg = GameConfig.Attribute.getElement(attrType)
            // if (!attrCfg) continue
            // 常规属性增加
            // Notice.showSecondNoticeWithAttribute(attrType, addVal);
        }
        this.syncPlayerStashedAttribute();
    }

    // 同步玩家数据到缓存数据
    private syncPlayerStashedAttribute() {
        Object.assign(this.playerStashedAttrBuffer, this.data.reserveAttribute);
    }

    // 服务器发送的请求玩家233名称
    net_get_nick_name() {
        let name = AccountService.getNickName()
        if(SystemUtil.isPIE){
            name = `本地玩家${this.localPlayerId}`
        }
        this.server.net_nick_name(name)
    }
    // 服务器发送的初始化属性列表
    net_init_attr(attributeArray: Attribute.AttributeArray) {
        for (let type in attributeArray) {
            let val = attributeArray[type];
            let typeKey = Number(type)
            this.attribute.setAttribute(typeKey, val);
            if(SystemUtil.isPIE){
                console.log(`属性变更:${typeKey}:${val}`);
            }
        }
    }
    // 服务器发送的属性变更
    net_change_attr(type: Attribute.EnumAttributeType, value: number) {
        this.attribute.setAttribute(type, value);
    }
}

export class PlayerModuleS extends ModuleS<PlayerModuleC, PlayerModuleData>{
    private appearanceMapping: Map<number, Appearance> = new Map()
    private playerAttributeMap: Map<number, Attribute.AttributeValueObject> = new Map();

    protected onPlayerEnterGame(player: mw.Player) {
        // 空名字
        player.character.asyncReady().then(character => { character.displayName = " " })
        // 初始化玩家信息脚本
        this.initPlayerAppearanceScript(player)
        // 初始化玩家属性
        this.initPlayerAttribute(player.playerId)
        // 计算属性
        this.recalculateAllAttribute(player)
    }

    protected onPlayerLeft(player: mw.Player): void {
        // 外观
        if (this.appearanceMapping.has(player.playerId)) {
            let appearance = this.appearanceMapping.get(player.playerId)
            appearance.destroy()
            this.appearanceMapping.delete(player.playerId)
        }
        // 属性
        this.playerAttributeMap.delete(player.playerId);
    }
    
    reducePlayerAttr(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        if (!Player.getPlayer(playerID)) return //已下线
        if (Attribute.IsStashAttribute(type)) {
            this.reducePlayerAttrStash(playerID, type, value);
            return
        }
        this.reducePlayerAttrIT(playerID, type, value);
    }

    addPlayerAttr(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        if (!Player.getPlayer(playerID)) return //已下线
        if (Attribute.IsStashAttribute(type)) {
            this.addPlayerAttrStash(playerID, type, value);
            return
        }
        this.addPlayerAttrIT(playerID, type, value);
    }
    
    getPlayerAttr(playerID: number, type: Attribute.EnumAttributeType): number {
        if (!Player.getPlayer(playerID)) return 0 //已下线
        // 是否为存储属性
        if (Attribute.IsStashAttribute(type)) {
            return this.getPlayerData(playerID).reserveAttribute[type] || 0;
        }
        return this.playerAttributeMap.get(playerID).getValue(type);
    }
    
    // 重新计算计算玩家所有属性并存储
    recalculateAllAttribute(player: Player) {
        let attrVo: Attribute.AttributeValueObject = new Attribute.AttributeValueObject();
        let playerID = player.playerId; 

        let growData = DataCenterS.getData(playerID, GrowModuleData)
        for (const key in growData.growMap) {
            let growCfgID = growData.growMap[key]
            let growCfg = GameConfig.Grow.getElement(growCfgID)
            attrVo.addValue(growCfg.AttributeType, growCfg.Value)
        }
        // 保存
        this.playerAttributeMap.set(playerID, attrVo);
        // 同步
        this.getClient(playerID).net_init_attr(attrVo.attributeArray);
    }

    // 减少玩家储存属性(不随游戏结束清空的属性)
    private reducePlayerAttrStash(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let data = this.getPlayerData(playerID);
        data.reserveAttribute[type] = data.reserveAttribute[type] - value;
        data.save(true);
    }

    // 增加玩家储存属性(不随游戏结束清空的属性)
    private addPlayerAttrStash(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let data = this.getPlayerData(playerID);
        data.reserveAttribute[type] += value;
        data.save(true);
    }

    // 减少玩家即时属性
    private reducePlayerAttrIT(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let vo = this.playerAttributeMap.get(playerID);
        vo.reduceValue(type, value);
        this.syncChangePlayerAttr(playerID, type);
    }

    // 增加玩家即时属性
    private addPlayerAttrIT(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let vo = this.playerAttributeMap.get(playerID);
        vo.addValue(type, value);
        this.syncChangePlayerAttr(playerID, type);
    }
    
    // 同步属性变更(单一)
    private syncChangePlayerAttr(playerID: number, type: Attribute.EnumAttributeType) {
        let attrVo = this.playerAttributeMap.get(playerID);
        this.getClient(playerID).net_change_attr(type, attrVo.getValue(type));
    }

    // 初始化玩家外观脚本
    private async initPlayerAppearanceScript(player: Player) {
        let playerID = player.playerId
        if (this.appearanceMapping.has(playerID)) return

        let appearance = await Script.spawnScript(Appearance)
        appearance.init(playerID)
        appearance.playerName = ' ' // 不加这个有问题

        this.appearanceMapping.set(playerID, appearance)

        this.getClient(player.playerId).net_get_nick_name()
    }

    // 初始化玩家属性
    private initPlayerAttribute(playerID:number){
        if(!this.playerAttributeMap.has(playerID)){
            let attrVo = new Attribute.AttributeValueObject()
            this.playerAttributeMap.set(playerID, attrVo)
        }
    }

    net_nick_name(name: string) {
        if(!this.appearanceMapping.has(this.currentPlayerId)) return
        this.appearanceMapping.get(this.currentPlayerId).playerName = name
    }

    net_add_money() {
        this.addPlayerAttr(this.currentPlayerId, Attribute.EnumAttributeType.money, 50)
    }
}